package crmdna.common;

import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import com.google.appengine.api.users.User;
import crmdna.common.APIResponse.Status;

public class Utils {
			
	public static Set<String> getQSTags(String... fields) {
		Set<String> set = new TreeSet<>();
		
		for (int i = 0; i < fields.length; i++) {
			if (fields[i] == null)
				continue;
			
			fields[i] = fields[i].toLowerCase();
			if (fields[i].length() < 3)
				continue;
			
			for (int beginIndex = 0; beginIndex < fields[i].length() - 2; beginIndex++) {
				set.add(fields[i].substring(beginIndex, beginIndex + 3));
			}
		}
		
		return set;
	}
	
	public static boolean closeEnough(String s1, String s2) {
		
		if ((s1 == null) || (s2 == null))
			return false;
		
		s1 = s1.toLowerCase().replaceAll(" ", "");
		s2 = s2.toLowerCase().replaceAll(" ", "");
		
		//if less than or equal to 3 char, entire string should match
		if (s1.length() <= 3)
			return s1.equals(s2);
		
		//if first 3 chars match return true
		if (s1.substring(0, 3).equals(s2.substring(0, 3)))
			return true;
		
		Set<String> s1QSTags = getQSTags(s1);
		Set<String> s2QSTags = getQSTags(s2);
		
		s1QSTags.retainAll(s2QSTags);
			
		return s1QSTags.size() > Math.min(s1.length(), s1.length())/3;		
	}
	
	public static boolean isValidEmailAddress(String email) {
		if (null == email)
			return false;
		
	    boolean stricterFilter = true; 
	    String stricterFilterString = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
	    String laxString = ".+@.+\\.[A-Za-z]{2}[A-Za-z]*";
	    String emailRegex = stricterFilter ? stricterFilterString : laxString;
	    java.util.regex.Pattern p = java.util.regex.Pattern.compile(emailRegex);
	    java.util.regex.Matcher m = p.matcher(email);
	    return m.matches();
	}
   
    public static boolean isPresentInListCaseInsensitive(List<String> list, 
			String s) {
		
		if ((null == list) || (null == s)) 
			return false;
		
		for (String element : list) {
			if (element.equalsIgnoreCase(s))
				return true;
		}
		
		return false;
	}
    
    public static String getLoginEmail(User user) {
    	if (null == user)
    		return null;
    	
    	return user.getEmail();
    }
    
    public static void throwIncorrectSpecException(String message) {
    	throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
    			message);
    }
    
    public static void throwNotFoundException(String message) {
    	throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
    			message);
    }
    
    public static void ensureValidPhoneNumber(String phoneNumber) {
		final String phoneNumberRegex =  "\\+(9[976]\\d|8[987530]\\d|6[987]\\d|5[90]\\d|42\\d|3[875]\\d|" +
				"2[98654321]\\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|" + 
				"4[987654310]|3[9643210]|2[70]|7|1)\\d{1,14}$";
		
		if ((phoneNumber == null) || (phoneNumber.equals("")))
			throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
					"Phone number cannot be null or empty");
		
		if (phoneNumber.charAt(0) != '+')
			throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
					"First character of phone number should be +");
		
		if (! phoneNumber.matches(phoneNumberRegex))
			throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
					"Phone number is invalid");				
	}
    
    public static boolean isValidPhoneNumber(String phoneNumber) {
    	throw new APIException(Status.ERROR_NOT_IMPLEMENTED, "not yet implemented");
    }
	
	public static void ensureValidEmail(String email) {
		if ((email == null) || (email.equals("")))
			throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
					"Email cannot be null or empty");
		
		boolean valid = Utils.isValidEmailAddress(email);			
		
		if (valid == false)
			throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
				"Email [" + email + "] is invalid");
    }	
	
	public static void ensureFormatYYYYMMDD(long date) {
		
		boolean valid = isFormatInYYYYMMDD(date);
		if (! valid)
			throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
					"[" + date + "] is not valid. Date should be valid in YYYYMMDD format");							
	}
	
	public static boolean isFormatInYYYYMMDD(long date) {
		String s = "" + date;
		
		if (s.length() != 8) 
			return false;			
		
		int year = Integer.parseInt(s.substring(0, 4));
		int month = Integer.parseInt(s.substring(4, 6));
		int day = Integer.parseInt(s.substring(6, 8));			
		
		if ((year < 1970) || (year > 2050))
			return false;
		
		if ((month < 1) || (month > 12))
			return false;
		
		if ((day < 1) || (day > 31))
			return false;
		
		if (month == 2) {
			if (day > 29)
				return false;
			
			if ((day == 29) && (year % 4 != 0)) 
				return false;
		}
		
		if ((month == 4) || (month == 6) || (month == 9) || (month == 11))
			if (day == 31)
				return false;
		
		return true;
	}
	
	public static String toDDMMMYY(long dateYYYYMMDD) {
		ensureFormatYYYYMMDD(dateYYYYMMDD);
		
		String s = "" + dateYYYYMMDD;
		
		int year = Integer.parseInt(s.substring(2, 4));
		int month = Integer.parseInt(s.substring(4, 6));
		int day = Integer.parseInt(s.substring(6, 8));
		
		return day + " " + get3CharMonth(month) + " " + year;				
	}
	
	public static String toDDMMM(long dateYYYYMMDD) {
		ensureFormatYYYYMMDD(dateYYYYMMDD);
		
		String s = "" + dateYYYYMMDD;
			
		int month = Integer.parseInt(s.substring(4, 6));
		int day = Integer.parseInt(s.substring(6, 8));
		
		return day + " " + get3CharMonth(month);				
	}
	
	public static String get3CharMonth(int month) {
		if (1 == month)
			return "Jan";
		
		if (2 == month)
			return "Feb";
		
		if (3 == month)
			return "Mar";
		
		if (4 == month)
			return "Apr";
		
		if (5 == month)
			return "May";
		
		if (6 == month)
			return "Jun";
		
		if (7 == month)
			return "Jul";
		
		if (8 == month)
			return "Aug";
		
		if (9 == month)
			return "Sep";
		
		if (10 == month)
			return "Oct";
		
		if (11 == month)
			return "Nov";
		
		if (12 == month)
			return "Dec";
		
		throw new APIException(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED, 
				"Invalid month [" + month + "]");
	}
	
	public static String getDurationAsString(long startYYYYMMDD, long endYYYYMMDD) {
		ensureFormatYYYYMMDD(startYYYYMMDD);
		ensureFormatYYYYMMDD(endYYYYMMDD);
		
		if (startYYYYMMDD > endYYYYMMDD)
			throw new APIException(Status.ERROR_RESOURCE_NOT_FULLY_SPECIFIED, 
					"Start date should not be greater than end date");
		
		if (startYYYYMMDD == endYYYYMMDD)
			return Utils.toDDMMMYY(startYYYYMMDD);
		
		String s = "" + startYYYYMMDD;		
		int yearStart = Integer.parseInt(s.substring(0, 4));
		int monthStart = Integer.parseInt(s.substring(4, 6));
		int dayStart = Integer.parseInt(s.substring(6, 8));
		
		s = "" + endYYYYMMDD;
		int yearEnd = Integer.parseInt(s.substring(0, 4));
		int monthEnd = Integer.parseInt(s.substring(4, 6));		
		
		if (yearStart == yearEnd) {
			if (monthStart == monthEnd) {
				return dayStart + " - " + toDDMMMYY(endYYYYMMDD);
			}
			
			return toDDMMM(startYYYYMMDD) + " - " + toDDMMMYY(endYYYYMMDD);
		}
		
		return toDDMMM(startYYYYMMDD) + " - " + toDDMMMYY(endYYYYMMDD);		
	}
	
	public static String getDateDiff(long startTimeInSeconds, long endTimeInSeconds) {
		long diff = endTimeInSeconds - startTimeInSeconds;
		if (diff < 0)
			Utils.throwIncorrectSpecException("startTimeInSeconds greater than endTimeInSeconds");
		
		if (diff < 60)
			return diff + " seconds";
		
		if (diff < 3600) {
			long min = Math.round(diff / 60.0);
			return min + " minute(s)";
		}
		
		if (diff < 3600 * 24) {
			long hours = Math.round(diff / 3600.0);
			return hours + " hour(s)";
		}
		
		long days = Math.round(diff / 3600.0 / 24.0);
		return days + " day(s)";
	}
}
